Skip to content

Conversation

@ThisGuyCodes
Copy link
Contributor

@ThisGuyCodes ThisGuyCodes commented Oct 30, 2025

Description

Terragrunt does not support using variables in the source or version fields of module blocks, but OpenTofu does.

This becomes a problem because when validating inputs via terragrunt hcl validate --inputs we use github.com/hashicorp/terraform-config-inspect to read the variables defined by the target module; since this is a Go module designed for Terraform it returns error diagnostics when variables are used as defined above.

Thus a valid OpenTofu module will fail a run of terragrunt hcl validate -inputs.

Fixes #4986

Despite these error diagnostics, as long as the syntax is valid we don't actually care (we just want to know what variables are defined, and if they have defaults defined).

This PR totally removes this use of github.com/hashicorp/terraform-config-inspect , instead parsing the Terraform / Tofu code just for variable definitions, ignoring everything else (our goal is validating the Terragrunt code anyway, validating the Tofu / Terraform code should be left to the respective tools).

Also reworded the docs on --inputs, as I found it a bit confusing.

TODOs

  • I authored this code entirely myself
  • I am submitting code based on open source software (e.g. MIT, MPL-2.0, Apache)]
  • I am adding or upgrading a dependency or adapted code and confirm it has a compatible open source license
  • Update the docs.
  • Run the relevant tests successfully, including pre-commit checks.
  • Include release notes. If this PR is backward incompatible, include a migration guide.

Release Notes (draft)

Allow variables in module source / version

Summary by CodeRabbit

  • Bug Fixes

    • Improved Terraform module variable parsing and detection accuracy, including broader file-format support.
  • Tests

    • Expanded test coverage with fixtures for edge cases: variables in module fields, circular references, invalid locals, and required/optional inputs. Added integration tests validating successful hcl validation.
  • Documentation

    • Clarified HCL validation docs to state that modules require certain variables.
  • Chores

    • Updated formatting config to exclude test fixtures from automatic formatting.

@ThisGuyCodes ThisGuyCodes self-assigned this Oct 30, 2025
@vercel
Copy link

vercel bot commented Oct 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
terragrunt-docs Ready Ready Preview Comment Nov 3, 2025 6:52am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

📝 Walkthrough

Walkthrough

Replaced tfconfig-based module parsing with explicit HCL/JSON parsing to detect module variables (required vs optional) even when variables appear in module source/version. Added fixtures and an integration test covering variable-in-source/version, circular refs, invalid locals, and required-input cases; updated docs and pre-commit config.

Changes

Cohort / File(s) Summary
Documentation update
docs-starlight/src/data/flags/hcl-validate-inputs.mdx
Adjusted front matter and descriptive text to say "variables a module requires" instead of "variables set by the module a unit provisions."
Core parsing logic
tf/tf.go
Replaced tfconfig.LoadModule parsing with manual HCL/JSON parsing: reads module directory, filters .tf/.tofu/.json, parses per-file, aggregates diagnostics and merged HCL body, extracts variable blocks via PartialContent, classifies required vs optional by presence of default, and returns (required, optional, error). Public signature unchanged.
Integration test
test/integration_test.go
Added TestHclvalidateValidConfig with subtests: runs terragrunt hcl validate --all --strict --inputs on valid fixtures and validates each valid subdirectory individually in parallel.
Test fixtures — variables in module fields
test/fixtures/hclvalidate/valid/var-in-source/*
test/fixtures/hclvalidate/valid/var-in-version/*
Added fixtures where module source or version uses a local variable; include main.tf and intentionally-blank terragrunt.hcl.
Test fixtures — edge cases
test/fixtures/hclvalidate/valid/circular-reference/*
test/fixtures/hclvalidate/valid/invalid-local/*
test/fixtures/hclvalidate/valid/single-required-input/*
Added fixtures for circular local references, undefined local reference, and a single required input variable; each includes main.tf and terragrunt.hcl as appropriate.
Pre-commit configuration
.pre-commit-config.yaml
Removed extra leading space in rev and added exclude pattern test/fixtures/hclvalidate/valid/.* to the tofu-fmt hook to skip formatting those fixtures.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as terragrunt hcl validate
    participant Parser as tf/tf.go (new HCL/JSON)
    participant Files as Module files (.tf/.tofu/.json)
    participant Vars as Variable extraction

    rect rgb(240,255,240)
    Caller->>Parser: Request ModuleVariables(modulePath)
    Parser->>Files: Read directory, filter target files
    Files-->>Parser: File contents
    Parser->>Parser: Parse .tf/.tofu with HCL parser\nParse .json with JSON parser
    Parser->>Parser: Aggregate diagnostics, merge HCL bodies
    end

    rect rgb(255,250,240)
    Parser->>Vars: PartialContent(variable block schema)
    Vars-->>Parser: variable blocks
    Parser->>Parser: For each variable: if default -> optional else -> required
    Parser-->>Caller: (requiredVars, optionalVars, error/diagnostics)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to pay attention to:
    • Variable detection logic in tf/tf.go (PartialContent schema and default-attribute handling).
    • Aggregation and formatting of parsing diagnostics across multiple files.
    • JSON parsing path equivalence with HCL parsing.
    • Integration test expectations and fixture correctness.

Possibly related issues

Suggested reviewers

  • denis256
  • yhakbar

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title "allow input validation with variable in source or version" is clear, concise, and directly reflects the primary objective of the pull request. It accurately summarizes the main change—enabling input validation for modules that use variables or locals in module source or version fields. The title avoids vague terminology and noise, making it easy for teammates reviewing history to understand the core contribution of this changeset.
Linked Issues Check ✅ Passed The code changes directly address the core requirement from issue #4986: enabling input validation when modules use variables or locals in source or version fields. The primary implementation change in tf/tf.go switches from terraform-config-inspect (which emits "Variables not allowed" diagnostics) to an HCL-based parsing approach that extracts variable definitions without generating such diagnostics. Supporting test fixtures (var-in-source, var-in-version) validate that variables in these contexts are now handled correctly, and the integration test confirms validation succeeds in these scenarios. The public function signature remains unchanged, and the implementation appropriately determines variable necessity based on default attribute presence.
Out of Scope Changes Check ✅ Passed All changes in the pull request are appropriately scoped to the stated objectives. The core implementation change (tf/tf.go) directly addresses the issue of allowing variables in source/version fields. Documentation updates to hcl-validate-inputs.mdx align with the PR's mentioned goal of rewording the --inputs flag documentation. New test fixtures (var-in-source, var-in-version, circular-reference, invalid-local, single-required-input) and the integration test are all necessary to validate the feature works correctly. The .pre-commit-config.yaml change (excluding test fixtures from tofu-fmt) is a reasonable housekeeping change related to the new test structure. No extraneous or unrelated changes are present.
Description check ✅ Passed The PR description adequately covers the problem, solution, and impact. All required TODOs are checked except dependency/license items (not applicable here), docs are updated, tests pass, and release notes are provided.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch thisguycodes/allow-vars-in-source-version

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

---

When enabled, Terragrunt will validate that all variables are set by the module a unit provisions.
When enabled, Terragrunt will validate that all variables a module (provisioned by a unit) requires are set.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to input on this, or even removing it. But I definitely don't think the current wording is correct (since we're checking that the unit sets variables consumed by the module, the module doesn't set them).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would better wording be: "When enabled, Terragrunt will validate that all inputs set by Terragrunt units are valid OpenTofu/Terraform variables consumed by their respective modules"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that only is accurate when using --strict, without --strict you can set inputs that are not consumed / don't exist as variables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to make an even more minimal example than the one in #4986

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know empty files seem silly, but in the spirit of "minimal reproduction" I don't think you can get more minimal than empty!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing wrong with it! If you want to be explicit about this, you can leave a one-line comment in the file that it's intentionally empty.

Comment on lines 620 to 628
t.Run("using --all", func(t *testing.T) {
t.Parallel()
helpers.CleanupTerraformFolder(t, testFixtureHclvalidate)
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureHclvalidate)
rootPath := util.JoinPath(tmpEnvPath, testFixtureHclvalidate)

_, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt hcl validate --all --strict --inputs --working-dir "+path.Join(rootPath, "valid"))
require.NoError(t, err)
})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this test, but actually it was already passing! Is --all not supposed to return non-zero?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's entirely possible there's a bug in the error handling. I think it should be returning an error if anything fails during an --all run.

@ThisGuyCodes ThisGuyCodes marked this pull request as ready for review October 31, 2025 04:47
tf/tf.go Outdated
Comment on lines 135 to 143
ignorableErrors := []tfconfig.Diagnostic{
// These two occur when a module block uses a variable in the `version` or `source` fields.
// Terraform doesn't support this, but OpenTofu does. Either way our ability to extract variables is unaffected.
//
// What we really need is an OpenTofu version of terraform-config-inspect. This may work for now but as / if
// syntax continues to diverge we may run into other issues.
{Summary: "Variables not allowed", Detail: "Variables may not be used here."},
{Summary: "Unsuitable value type", Detail: "Unsuitable value: value must be known"},
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to keep this scoped to this function, plus putting it outside the function would require a more descriptive name.

I'm 90% sure the compiler notices it's never changed and pre-allocates it, but am happy to be proven wrong (and will move it if so).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a big deal either way.

@ThisGuyCodes ThisGuyCodes changed the title [WIP] allow input validation with variable in source or version allow input validation with variable in source or version Oct 31, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between adad0cb and 6017839.

📒 Files selected for processing (5)
  • docs-starlight/src/data/flags/hcl-validate-inputs.mdx (1 hunks)
  • test/fixtures/hclvalidate/valid/var-in-source/main.tf (1 hunks)
  • test/fixtures/hclvalidate/valid/var-in-version/main.tf (1 hunks)
  • test/integration_test.go (1 hunks)
  • tf/tf.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
docs-starlight/**/*.md*

⚙️ CodeRabbit configuration file

Review the documentation for clarity, grammar, and spelling. Make sure that the documentation is easy to understand and follow. There is currently a migration underway from the Jekyll based documentation in docs to the Starlight + Astro based documentation in docs-starlight. Make sure that the docs-starlight documentation is accurate and up-to-date with the docs documentation, and that any difference between them results in an improvement in the docs-starlight documentation.

Files:

  • docs-starlight/src/data/flags/hcl-validate-inputs.mdx
**/*.go

⚙️ CodeRabbit configuration file

Review the Go code for quality and correctness. Make sure that the Go code follows best practices, is performant, and is easy to understand and maintain.

Files:

  • tf/tf.go
  • test/integration_test.go
🧠 Learnings (2)
📚 Learning: 2025-08-19T16:05:54.723Z
Learnt from: Resonance1584
Repo: gruntwork-io/terragrunt PR: 4683
File: go.mod:86-90
Timestamp: 2025-08-19T16:05:54.723Z
Learning: When analyzing Go module dependencies for removal, always check for both direct imports and API usage across all Go files in the repository, not just a quick search. The github.com/mattn/go-zglob library is used for filesystem walking and glob expansion in multiple Terragrunt files including util/file.go, format commands, and AWS provider patch functionality.

Applied to files:

  • tf/tf.go
📚 Learning: 2025-02-10T13:36:19.542Z
Learnt from: levkohimins
Repo: gruntwork-io/terragrunt PR: 3723
File: cli/commands/stack/action.go:160-160
Timestamp: 2025-02-10T13:36:19.542Z
Learning: The project uses a custom error package `github.com/gruntwork-io/terragrunt/internal/errors` which provides similar functionality to `fmt.Errorf` but includes stack traces. Prefer using this package's error functions (e.g., `errors.Errorf`, `errors.New`) over the standard library's error handling.

Applied to files:

  • tf/tf.go
🧬 Code graph analysis (2)
tf/tf.go (1)
internal/view/diagnostic/diagnostic.go (1)
  • Diagnostic (21-27)
test/integration_test.go (2)
test/helpers/package.go (3)
  • CleanupTerraformFolder (879-886)
  • CopyEnvironment (89-102)
  • RunTerragruntCommandWithOutput (1004-1008)
util/file.go (1)
  • JoinPath (626-628)
🪛 Checkov (3.2.334)
test/fixtures/hclvalidate/valid/var-in-source/main.tf

[medium] 5-8: Ensure Terraform module sources use a commit hash

(CKV_TF_1)


[high] 5-8: Ensure Terraform module sources use a tag with a version number

(CKV_TF_2)

test/fixtures/hclvalidate/valid/var-in-version/main.tf

[medium] 5-8: Ensure Terraform module sources use a commit hash

(CKV_TF_1)


[high] 5-8: Ensure Terraform module sources use a tag with a version number

(CKV_TF_2)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Pull Request has non-contributor approval
  • GitHub Check: base_tests / Test (macos)
  • GitHub Check: base_tests / Test (ubuntu)
  • GitHub Check: Pull Request has non-contributor approval

tf/tf.go Outdated
return true
}

i := slices.IndexFunc(ignorableErrors, func(ie tfconfig.Diagnostic) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that this can be simplified to

	return slices.ContainsFunc(ignorableErrors, func(ie tfconfig.Diagnostic) bool {
		return ie.Summary == d.Summary && ie.Detail == d.Detail
	})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes way more sense. I already know about contains so I don't know what I was thinking when I wrote this

yhakbar
yhakbar previously approved these changes Oct 31, 2025
Copy link
Collaborator

@yhakbar yhakbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this does the job, so I'll approve it. It's not how I thought you'd tackle this.

I was assuming you'd do something like this untested code:

type Variable struct {
	Name    string `hcl:"name,label"`
	Default string `hcl:"default,optional"`

	Remainder hcl.Body `hcl:",remain"`
}

type ModuleVars struct {
	Variables []Variable `hcl:"variable,block"`
}

// ModuleVariables will return all the variables defined in the downloaded terraform modules, taking into
// account all the generated sources. This function will return the required and optional variables separately.
func ModuleVariables(modulePath string) ([]string, []string, error) {
	parser := hclparse.NewParser()

	files, err := os.ReadDir(modulePath)
	if err != nil {
		return nil, nil, err
	}

	hclFiles := []*hcl.File{}
	errs := []error{}

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		// This would only solve the issue for HCL files. We'd need to also check JSON files.
		if !strings.HasSuffix(file.Name(), ".tf") && !strings.HasSuffix(file.Name(), ".tofu") {
			continue
		}

		hclFile, err := parser.ParseFromFile(file.Name())
		if err != nil {
			errs = append(errs, err)
		}

		hclFiles = append(hclFiles, hclFile.File)
	}

	if len(errs) > 0 {
		return nil, nil, errors.New(errs)
	}

	body := hcl.MergeFiles(hclFiles)

	moduleVars := ModuleVars{}

	if err := gohcl.DecodeBody(body, nil, &moduleVars); err != nil {
		return nil, nil, err
	}

	required := []string{}
	optional := []string{}

	for _, variable := range moduleVars.Variables {
		if variable.Default != "" {
			optional = append(optional, variable.Name)
		}
	}

	return required, optional, nil
}

To fully drop the dependency on github.com/hashicorp/terraform-config-inspect/tfconfig.

It's a bigger change than what you're doing here, so I'll accept that you might prefer your current solution. Please confirm that you've evaluated this, and don't want to make this or the changes that @denis256 recommended before merging if you're happy with the solution.

---

When enabled, Terragrunt will validate that all variables are set by the module a unit provisions.
When enabled, Terragrunt will validate that all variables a module (provisioned by a unit) requires are set.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would better wording be: "When enabled, Terragrunt will validate that all inputs set by Terragrunt units are valid OpenTofu/Terraform variables consumed by their respective modules"?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing wrong with it! If you want to be explicit about this, you can leave a one-line comment in the file that it's intentionally empty.

Comment on lines 620 to 628
t.Run("using --all", func(t *testing.T) {
t.Parallel()
helpers.CleanupTerraformFolder(t, testFixtureHclvalidate)
tmpEnvPath := helpers.CopyEnvironment(t, testFixtureHclvalidate)
rootPath := util.JoinPath(tmpEnvPath, testFixtureHclvalidate)

_, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt hcl validate --all --strict --inputs --working-dir "+path.Join(rootPath, "valid"))
require.NoError(t, err)
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's entirely possible there's a bug in the error handling. I think it should be returning an error if anything fails during an --all run.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the names on these fixtures. Reading the name of the fixture should tell you what the fixture is for.

tf/tf.go Outdated
Comment on lines 135 to 143
ignorableErrors := []tfconfig.Diagnostic{
// These two occur when a module block uses a variable in the `version` or `source` fields.
// Terraform doesn't support this, but OpenTofu does. Either way our ability to extract variables is unaffected.
//
// What we really need is an OpenTofu version of terraform-config-inspect. This may work for now but as / if
// syntax continues to diverge we may run into other issues.
{Summary: "Variables not allowed", Detail: "Variables may not be used here."},
{Summary: "Unsuitable value type", Detail: "Unsuitable value: value must be known"},
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a big deal either way.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
tf/tf.go (2)

162-164: Avoid allocating slice on every iteration.

The slice []string{"tf", "tofu", "json"} is allocated on every loop iteration. Define it once outside the loop or use a switch statement for better performance.

Apply this diff:

+	validExtensions := []string{"tf", "tofu", "json"}
+
 	for _, file := range files {
 		if file.IsDir() {
 			continue
 		}
+
 		parseFunc := parser.ParseHCLFile
-		suffix := ""
-		for s := range strings.SplitSeq(file.Name(), ".") {
-			suffix = s
-		}
-		if suffix == "json" {
+		ext := path.Ext(file.Name())
+		if len(ext) > 0 {
+			ext = ext[1:] // Remove leading dot
+		}
+
+		if ext == "json" {
 			parseFunc = parser.ParseJSONFile
 		}
 
-		if !(slices.Contains([]string{"tf", "tofu", "json"}, suffix)) {
+		if !slices.Contains(validExtensions, ext) {
 			continue
 		}
+
-		file, parseDiags := parseFunc(path.Join(modulePath, file.Name()))
+		parsedFile, parseDiags := parseFunc(path.Join(modulePath, file.Name()))
 
-		hclFiles = append(hclFiles, file)
+		hclFiles = append(hclFiles, parsedFile)
 		allDiags = append(allDiags, parseDiags...)
 	}

196-198: Consider adding context to error messages.

When diagnostics contain errors, it would be helpful to include information about which files caused the issues to aid debugging.

Consider enhancing the error message:

 	if allDiags.HasErrors() {
-		return nil, nil, errors.New(allDiags)
+		return nil, nil, errors.Errorf("failed to parse module at %s: %w", modulePath, errors.New(allDiags))
 	}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6017839 and 97170ba.

📒 Files selected for processing (13)
  • docs-starlight/src/data/flags/hcl-validate-inputs.mdx (1 hunks)
  • test/fixtures/hclvalidate/valid/circular-reference/main.tf (1 hunks)
  • test/fixtures/hclvalidate/valid/circular-reference/terragrunt.hcl (1 hunks)
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/main.tf (1 hunks)
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/terragrunt.hcl (1 hunks)
  • test/fixtures/hclvalidate/valid/invalid-local/main.tf (1 hunks)
  • test/fixtures/hclvalidate/valid/invalid-local/terragrunt.hcl (1 hunks)
  • test/fixtures/hclvalidate/valid/single-required-input/main.tf (1 hunks)
  • test/fixtures/hclvalidate/valid/single-required-input/terragrunt.hcl (1 hunks)
  • test/fixtures/hclvalidate/valid/var-in-source/terragrunt.hcl (1 hunks)
  • test/fixtures/hclvalidate/valid/var-in-version/terragrunt.hcl (1 hunks)
  • test/integration_test.go (1 hunks)
  • tf/tf.go (2 hunks)
✅ Files skipped from review due to trivial changes (6)
  • test/fixtures/hclvalidate/valid/var-in-source/terragrunt.hcl
  • test/fixtures/hclvalidate/valid/circular-reference/terragrunt.hcl
  • test/fixtures/hclvalidate/valid/var-in-version/terragrunt.hcl
  • test/fixtures/hclvalidate/valid/invalid-local/terragrunt.hcl
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/main.tf
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/terragrunt.hcl
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/integration_test.go
🧰 Additional context used
📓 Path-based instructions (2)
docs-starlight/**/*.md*

⚙️ CodeRabbit configuration file

Review the documentation for clarity, grammar, and spelling. Make sure that the documentation is easy to understand and follow. There is currently a migration underway from the Jekyll based documentation in docs to the Starlight + Astro based documentation in docs-starlight. Make sure that the docs-starlight documentation is accurate and up-to-date with the docs documentation, and that any difference between them results in an improvement in the docs-starlight documentation.

Files:

  • docs-starlight/src/data/flags/hcl-validate-inputs.mdx
**/*.go

⚙️ CodeRabbit configuration file

Review the Go code for quality and correctness. Make sure that the Go code follows best practices, is performant, and is easy to understand and maintain.

Files:

  • tf/tf.go
🧠 Learnings (3)
📚 Learning: 2025-08-19T16:05:54.723Z
Learnt from: Resonance1584
Repo: gruntwork-io/terragrunt PR: 4683
File: go.mod:86-90
Timestamp: 2025-08-19T16:05:54.723Z
Learning: When analyzing Go module dependencies for removal, always check for both direct imports and API usage across all Go files in the repository, not just a quick search. The github.com/mattn/go-zglob library is used for filesystem walking and glob expansion in multiple Terragrunt files including util/file.go, format commands, and AWS provider patch functionality.

Applied to files:

  • tf/tf.go
📚 Learning: 2025-02-10T13:36:19.542Z
Learnt from: levkohimins
Repo: gruntwork-io/terragrunt PR: 3723
File: cli/commands/stack/action.go:160-160
Timestamp: 2025-02-10T13:36:19.542Z
Learning: The project uses a custom error package `github.com/gruntwork-io/terragrunt/internal/errors` which provides similar functionality to `fmt.Errorf` but includes stack traces. Prefer using this package's error functions (e.g., `errors.Errorf`, `errors.New`) over the standard library's error handling.

Applied to files:

  • tf/tf.go
📚 Learning: 2025-02-10T23:20:04.295Z
Learnt from: yhakbar
Repo: gruntwork-io/terragrunt PR: 3868
File: docs-starlight/patches/@astrojs%[email protected]:33-33
Timestamp: 2025-02-10T23:20:04.295Z
Learning: In Terragrunt projects, all `.hcl` files can be assumed to be Terragrunt configurations by default, with specific exceptions like `.terraform.lock.hcl` that need explicit handling.

Applied to files:

  • test/fixtures/hclvalidate/valid/single-required-input/terragrunt.hcl
🪛 GitHub Actions: CI
tf/tf.go

[error] 153-153: wsl_v5: missing whitespace above this line (invalid statement above assign)


[error] 154-154: wsl_v5: missing whitespace above this line (too many statements above range)


[error] 158-158: wsl_v5: missing whitespace above this line (invalid statement above if)


[error] 165-165: wsl_v5: missing whitespace above this line (invalid statement above assign)


[error] 185-185: wsl_v5: missing whitespace above this line (no shared variables above range)


[error] 188-188: wsl_v5: missing whitespace above this line (too many statements above if)


[error] 199-199: wsl_v5: missing whitespace above this line (too many lines above return)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Pull Request has non-contributor approval
  • GitHub Check: Pull Request has non-contributor approval
🔇 Additional comments (5)
test/fixtures/hclvalidate/valid/circular-reference/main.tf (1)

1-4: LGTM! Appropriate edge case test fixture.

This fixture correctly tests that the HCL parser can handle circular local references without crashing during validation. While this would fail at runtime, it's valid syntax and an appropriate edge case for the validation logic.

test/fixtures/hclvalidate/valid/invalid-local/main.tf (1)

1-3: LGTM! Valid test for undefined reference handling.

This fixture appropriately tests that the validation logic can handle references to undefined locals without crashing. The syntax is valid HCL, making it a good test case for semantic validation.

test/fixtures/hclvalidate/valid/single-required-input/terragrunt.hcl (1)

1-3: LGTM! Clean test fixture.

This fixture correctly provides an input value for the required variable defined in the corresponding main.tf, making it suitable for testing input validation.

test/fixtures/hclvalidate/valid/single-required-input/main.tf (1)

1-2: LGTM! Correct required variable definition.

This fixture correctly defines a required variable (no default value) that pairs with the terragrunt.hcl input, making it suitable for testing required input validation.

docs-starlight/src/data/flags/hcl-validate-inputs.mdx (1)

3-3: LGTM! Clearer and more accurate documentation.

The updated wording correctly reflects that validation ensures units provide values for variables that modules require, rather than the previous confusing "set by the module" phrasing. This aligns well with the actual validation behavior.

Also applies to: 9-9

tf/tf.go Outdated
Comment on lines 153 to 156
parseFunc := parser.ParseHCLFile
suffix := ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix whitespace linting errors.

The pipeline reports multiple wsl_v5 linting failures for missing whitespace. Add blank lines as indicated by the linter to improve code readability and comply with project standards.

Based on the linting errors, add blank lines:

  • After line 152 (before line 153)
  • After line 153 (before line 154)
  • After line 157 (before line 158)
  • After line 164 (before line 165)
  • After line 184 (before line 185)
  • After line 187 (before line 188)
  • After line 198 (before line 199)

Also applies to: 158-158, 165-165, 185-185, 188-188, 199-199

🧰 Tools
🪛 GitHub Actions: CI

[error] 153-153: wsl_v5: missing whitespace above this line (invalid statement above assign)


[error] 154-154: wsl_v5: missing whitespace above this line (too many statements above range)

🤖 Prompt for AI Agents
In tf/tf.go around the region covering lines 152–199, the linter flagged missing
blank lines; add single blank lines after lines 152, 153, 157, 164, 184, 187,
and 198 (which also covers the specific spots 158, 165, 185, 188, 199 mentioned)
so each indicated line is followed by an empty line to satisfy wsl_v5 whitespace
rules and restore readability.

tf/tf.go Outdated
Comment on lines 165 to 172
file, parseDiags := parseFunc(path.Join(modulePath, file.Name()))

hclFiles = append(hclFiles, file)
allDiags = append(allDiags, parseDiags...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Variable shadowing detected.

The variable file on line 165 shadows the loop variable file from line 149, making the code confusing and error-prone.

Apply this diff:

-		file, parseDiags := parseFunc(path.Join(modulePath, file.Name()))
+		parsedFile, parseDiags := parseFunc(path.Join(modulePath, file.Name()))
 
-		hclFiles = append(hclFiles, file)
+		hclFiles = append(hclFiles, parsedFile)
 		allDiags = append(allDiags, parseDiags...)
🧰 Tools
🪛 GitHub Actions: CI

[error] 165-165: wsl_v5: missing whitespace above this line (invalid statement above assign)

🤖 Prompt for AI Agents
In tf/tf.go around lines 165 to 168, the local variable `file` returned from
parseFunc is shadowing the loop variable `file`; rename the value returned by
parseFunc (for example to `parsedFile` or `parsed`) and use that renamed
variable when appending to hclFiles and collecting diagnostics so the loop
variable remains unshadowed and the code is clear.

@ThisGuyCodes
Copy link
Contributor Author

ThisGuyCodes commented Nov 3, 2025

@yhakbar I had considered it, and really would prefer it, but I had two thoughts:

  1. I'd have to define the schema we expect, this duplication of schema (the "original" being inside terraform / opentofu) is a pattern that makes me even more itchy about drift.
    • The code as you wrote would produce error diagnostics on anything that isn't a variable block (it infers the schema from the struct tags, then "requires" that all the hcl match the schema)
  2. We'd be potentially allowing an even wider set of "invalid" Tofu / Terraform code than intended. Strictly speaking this code path is only meant to validate the Terragrunt files; but at present it also does some implicit validation of Tofu / Terraform code structure.

However text in the terraform-config-inspect readme made a really good point about the compatibility promise (alleviating the first point), and the presence of your suggestion mostly alleviates my concern for the second point (since it implies you're not concerned about this sort of implicit validation), so I went ahead and did it.

I also added more test cases, some I just thought of when thinking about this "implicit validation" thing; and one specifically that currently fails (using tfconfig), and will pass when we do our own parsing never mind I was wrong. I apparently cannot come up with a case that will behave the way I thought this would!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tf/tf.go (1)

5-5: Consider using path/filepath instead of path for file system operations.

The path package is designed for slash-separated paths (canonical/URL-style), while path/filepath handles OS-specific path separators (e.g., backslash on Windows). Since this function works with file system paths from os.ReadDir and joins them on line 169, using filepath.Join would ensure better cross-platform compatibility.

Apply this diff:

 import (
 	"os"
-	"path"
+	"path/filepath"
 	"slices"

Then update line 169:

-	file, parseDiags := parseFunc(path.Join(modulePath, file.Name()))
+	file, parseDiags := parseFunc(filepath.Join(modulePath, file.Name()))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c52da2 and e9a8894.

📒 Files selected for processing (3)
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/main.tf (1 hunks)
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/terragrunt.hcl (1 hunks)
  • tf/tf.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/terragrunt.hcl
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

Review the Go code for quality and correctness. Make sure that the Go code follows best practices, is performant, and is easy to understand and maintain.

Files:

  • tf/tf.go
🧠 Learnings (3)
📚 Learning: 2025-08-19T16:05:54.723Z
Learnt from: Resonance1584
Repo: gruntwork-io/terragrunt PR: 4683
File: go.mod:86-90
Timestamp: 2025-08-19T16:05:54.723Z
Learning: When analyzing Go module dependencies for removal, always check for both direct imports and API usage across all Go files in the repository, not just a quick search. The github.com/mattn/go-zglob library is used for filesystem walking and glob expansion in multiple Terragrunt files including util/file.go, format commands, and AWS provider patch functionality.

Applied to files:

  • tf/tf.go
📚 Learning: 2025-04-17T13:02:28.098Z
Learnt from: yhakbar
Repo: gruntwork-io/terragrunt PR: 4169
File: cli/commands/hcl/validate/cli.go:29-60
Timestamp: 2025-04-17T13:02:28.098Z
Learning: Avoid shadowing imported packages with local variables in Go code, such as using a variable named `flags` when the `github.com/gruntwork-io/terragrunt/cli/flags` package is imported. Use more specific variable names like `flagSet` instead.

Applied to files:

  • tf/tf.go
📚 Learning: 2025-02-10T13:36:19.542Z
Learnt from: levkohimins
Repo: gruntwork-io/terragrunt PR: 3723
File: cli/commands/stack/action.go:160-160
Timestamp: 2025-02-10T13:36:19.542Z
Learning: The project uses a custom error package `github.com/gruntwork-io/terragrunt/internal/errors` which provides similar functionality to `fmt.Errorf` but includes stack traces. Prefer using this package's error functions (e.g., `errors.Errorf`, `errors.New`) over the standard library's error handling.

Applied to files:

  • tf/tf.go
🪛 GitHub Actions: CI
test/fixtures/hclvalidate/valid/duplicate-attributes-in-required-providers/main.tf

[error] 4-4: Attribute redefined. The argument 'attr' was already set at 3,5-9. Each argument may be set only once.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Pull Request has non-contributor approval

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test case fails using the tfconfig package, but passes doing our own parsing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stand corrected! I swear I saw this pass locally, but apparently I was imagining things.

Copy link
Collaborator

@yhakbar yhakbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Great job!

@ThisGuyCodes ThisGuyCodes merged commit 63bdbef into main Nov 3, 2025
53 checks passed
@ThisGuyCodes ThisGuyCodes deleted the thisguycodes/allow-vars-in-source-version branch November 3, 2025 18:59
@rlees85
Copy link

rlees85 commented Nov 4, 2025

Awesome, thank you very much. I was really not expecting this problem to be resolved quickly or by somebody else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Terragrunt cannot validate inputs if Terraform module uses variables in "source" or "version" fields

5 participants